﻿using Reckoning;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;

namespace TestReckoning
{
    
    
    /// <summary>
    ///This is a test class for CountFilterTest and is intended
    ///to contain all CountFilterTest Unit Tests
    ///</summary>
    [TestClass()]
    public class CountFilterTest
    {


        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion


        /// <summary>
        ///A test for CountFilter Constructor
        ///</summary>
        [TestMethod()]
        public void CountFilterConstructorTest()
        {
            CountFilter target = new CountFilter();
            Assert.IsNotNull(target);
        }

        /// <summary>
        ///A test for Counting
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void CountingTest()
        {
            CountFilter_Accessor target = new CountFilter_Accessor();
            CountOptions countOpt = new CountOptions(true, true, null, 10, 100, false, null);
            uint totalWordCount = 4;
            Dictionary<string, uint> rawCounts = new Dictionary<string, uint>();
            rawCounts.Add("a", 1);
            rawCounts.Add("b", 3);
            Dictionary<string, double> referenceData = new Dictionary<string, double>();
            referenceData.Add("a", 1F);
            referenceData.Add("b", 3F);
            List<WordCountInfo> filteredCounts = new List<WordCountInfo>();
            List<WordCountInfo> filteredCountsExpected = new List<WordCountInfo>();            
            filteredCountsExpected.Add(new WordCountInfo("a", null, 1, 25, 1));
            filteredCountsExpected.Add(new WordCountInfo("b", null, 1, 75, 3));
            target.Counting(countOpt, totalWordCount, rawCounts, referenceData, ref filteredCounts);
            bool equal = (filteredCounts.Count == filteredCountsExpected.Count);
            for (int i = 0; i < filteredCounts.Count && equal; ++i)
            {
                if (filteredCounts[i].Ratio != filteredCountsExpected[i].Ratio)
                    equal = false;
            }
            Assert.IsTrue(equal);            
        }

        /// <summary>
        ///A test for Counting
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void CountingTest_NoReference()
        {
            CountFilter_Accessor target = new CountFilter_Accessor();
            CountOptions countOpt = new CountOptions(true, true, null, 10, 100, false, null);
            uint totalWordCount = 4;
            Dictionary<string, uint> rawCounts = new Dictionary<string, uint>();
            rawCounts.Add("a", 1);
            rawCounts.Add("b", 3);
            Dictionary<string, double> referenceData = null;
            List<WordCountInfo> filteredCounts = new List<WordCountInfo>();
            List<WordCountInfo> filteredCountsExpected = new List<WordCountInfo>();            
            filteredCountsExpected.Add(new WordCountInfo("a", null, 1, 25F, 0F));            
            filteredCountsExpected.Add(new WordCountInfo("b", null, 1, 75F, 0F));
            target.Counting(countOpt, totalWordCount, rawCounts, referenceData, ref filteredCounts);
            bool equal = (filteredCounts.Count == filteredCountsExpected.Count);
            for (int i = 0; i < filteredCounts.Count && equal; ++i)
            {
                if (filteredCounts[i].Ratio != filteredCountsExpected[i].Ratio)
                    equal = false;
            }
            Assert.IsTrue(equal);
        }

        /// <summary>
        ///A test for IsStopWord
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void IsStopWordTest()
        {
            CountFilter_Accessor target = new CountFilter_Accessor();
            HashSet<StopWordInfo> sw = new HashSet<StopWordInfo>();
            sw.Add(new StopWordInfo("the"));
            CountOptions countOpt = new CountOptions(true, true, sw, 10, 100, false, null);
            string word = "the";
            bool expected = true;
            bool actual = target.IsStopWord(countOpt, word);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for IsStopWord
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void IsStopWordTest_NotStopWord()
        {
            CountFilter_Accessor target = new CountFilter_Accessor();
            HashSet<StopWordInfo> sw = new HashSet<StopWordInfo>();
            sw.Add(new StopWordInfo("the"));
            CountOptions countOpt = new CountOptions(true, true, sw, 10, 100, false, null);
            string word = "a"; 
            bool expected = false; 
            bool actual = target.IsStopWord(countOpt, word);
            Assert.AreEqual(expected, actual);            
        }

        /// <summary>
        ///A test for IsStopWord
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void IsStopWordTest_NoStopWords()
        {
            CountFilter_Accessor target = new CountFilter_Accessor();
            CountOptions countOpt = new CountOptions(true, true, null, 10, 100, false, null);
            string word = string.Empty;
            bool expected = false;
            bool actual = target.IsStopWord(countOpt, word);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for ProcessReference
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void ProcessReferenceTest()
        {
            CountFilter_Accessor target = new CountFilter_Accessor();
            CountOptions countOpt = new CountOptions(true, true, null, 10, 100, true, "reference_data.xml");
            Dictionary<string, double> referenceData = new Dictionary<string, double>();
            Dictionary<string, double> referenceDataExpected = new Dictionary<string, double>();
            referenceDataExpected.Add("hello", 10F);
            referenceDataExpected.Add("goodbye", 90F);
            bool expected = true;
            bool actual = target.ProcessReference(countOpt, ref referenceData);
            bool equal = (referenceDataExpected.Count == referenceDataExpected.Count);
            foreach (KeyValuePair<string, double> pair in referenceDataExpected)
            {
                if (!referenceData.ContainsKey(pair.Key) || referenceData[pair.Key] != pair.Value)
                    equal = false;
            }
            Assert.IsTrue(equal);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for ProcessReference
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void ProcessReferenceTest_NotUsingReferenceData()
        {
            CountFilter_Accessor target = new CountFilter_Accessor();
            CountOptions countOpt = new CountOptions(true, true, null, 10, 100, false, null);
            Dictionary<string, double> referenceData = new Dictionary<string, double>();            
            bool expected = false; 
            bool actual = target.ProcessReference(countOpt, ref referenceData);
            Assert.IsTrue(referenceData.Count == 0);
            Assert.AreEqual(expected, actual);            
        }

        /// <summary>
        ///A test for ProcessReference
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void ProcessReferenceTest_BadPath()
        {
            CountFilter_Accessor target = new CountFilter_Accessor();
            CountOptions countOpt = new CountOptions(true, true, null, 10, 100, true, null);
            Dictionary<string, double> referenceData = new Dictionary<string, double>();
            bool expected = false;
            bool actual = target.ProcessReference(countOpt, ref referenceData);
            Assert.IsTrue(referenceData.Count == 0);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for ProcessReference
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void ProcessReferenceTest_EmptyFile()
        {
            string tmpPath = System.IO.Path.GetTempFileName();
            using (System.IO.StreamWriter tw = new System.IO.StreamWriter(tmpPath))
            {
                tw.WriteLine();
            }

            CountFilter_Accessor target = new CountFilter_Accessor();
            CountOptions countOpt = new CountOptions(true, true, null, 10, 100, true, tmpPath);
            Dictionary<string, double> referenceData = new Dictionary<string, double>();
            bool expected = false;
            bool actual = target.ProcessReference(countOpt, ref referenceData);
            System.IO.File.Delete(tmpPath);
            Assert.IsTrue(referenceData.Count == 0);
            Assert.AreEqual(expected, actual);            
        }

        /// <summary>
        ///A test for RankAndSort
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void RankAndSortTest()
        {
            CountFilter_Accessor target = new CountFilter_Accessor();
            List<WordCountInfo> filteredCounts = new List<WordCountInfo>();
            filteredCounts.Add(new WordCountInfo("x", null, 10, 1F, 0F));
            filteredCounts.Add(new WordCountInfo("sb", null, 10, 1F, 0F));
            filteredCounts.Add(new WordCountInfo("sa", null, 10, 1F, 0F));
            filteredCounts.Add(new WordCountInfo("z", null, 100, 10F, 0F));
            filteredCounts.Add(new WordCountInfo("a", null, 100, 10F, 0F));
            target.RankAndSort(ref filteredCounts);
            bool correct = (filteredCounts.Count == 5);            
            for (int i = 0; i < filteredCounts.Count; ++i)
            {
                if (filteredCounts[i].Rank != i + 1)
                    correct = false;

                else if (i > 0 && filteredCounts[i].Count > filteredCounts[i - 1].Count)
                    correct = false;

                else if (i > 0 && filteredCounts[i].Count == filteredCounts[i - 1].Count &&
                    filteredCounts[i].Word.CompareTo(filteredCounts[i - 1].Word) < 0)
                    correct = false;
            }

            Assert.IsTrue(correct);
        }

        /// <summary>
        ///A test for RankAndSort
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void RankAndSortTest_Empty()
        {
            CountFilter_Accessor target = new CountFilter_Accessor();
            List<WordCountInfo> filteredCounts = new List<WordCountInfo>();

            target.RankAndSort(ref filteredCounts);
            Assert.IsTrue(filteredCounts.Count == 0);
        }

        /// <summary>
        ///A test for Stemming
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void StemmingTest()
        {
            CountFilter_Accessor target = new CountFilter_Accessor();
            CountOptions countOpt = new CountOptions(true, false, null, 10, 100, false, null);
            uint totalWordCount = 5;
            Dictionary<string, uint> rawCounts = new Dictionary<string, uint>();
            rawCounts.Add("go", 1);
            rawCounts.Add("going", 3);
            rawCounts.Add("other", 1);
            Dictionary<string, double> referenceData = null;            
            List<WordCountInfo> filteredCounts = new List<WordCountInfo>();
            target.Stemming(countOpt, totalWordCount, rawCounts, referenceData, ref filteredCounts);

            bool correct = (filteredCounts.Count == 2 && 
                filteredCounts[0].Word == "go" && filteredCounts[0].Variants == "go (1), going (3)" && filteredCounts[0].Count == 4 &&
                filteredCounts[1].Word == "other" && filteredCounts[1].Variants == string.Empty && filteredCounts[1].Count == 1);

            Assert.IsTrue(correct);            
        }      

        /// <summary>
        ///A test for Threshold
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void ThresholdTest_Percent()
        {
            CountFilter_Accessor target = new CountFilter_Accessor();
            CountOptions countOpt = new CountOptions(true, false, null, 10, 30, false, null);
            uint totalWordCount = 500; 
            List<WordCountInfo> filteredCounts = new List<WordCountInfo>();            
            filteredCounts.Add(new WordCountInfo("x", null, 100, 20F, 0F));
            filteredCounts.Add(new WordCountInfo("sb", null, 100, 20F, 0F));
            filteredCounts.Add(new WordCountInfo("sa", null, 50, 10F, 0F));
            filteredCounts.Add(new WordCountInfo("z", null, 50, 10F, 0F));
            filteredCounts.Add(new WordCountInfo("a", null, 50, 10F, 0F));
            filteredCounts.Add(new WordCountInfo("b", null, 50, 10F, 0F));
            filteredCounts.Add(new WordCountInfo("c", null, 50, 10F, 0F));
            filteredCounts.Add(new WordCountInfo("d", null, 50, 10F, 0F));            
            List<WordCountInfo> finalCounts = new List<WordCountInfo>();
            target.Threshold(countOpt, totalWordCount, ref filteredCounts, ref finalCounts);

            Assert.IsTrue(finalCounts.Count == 2);
        }

        /// <summary>
        ///A test for Threshold
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void ThresholdTest_PercentTie()
        {
            CountFilter_Accessor target = new CountFilter_Accessor();
            CountOptions countOpt = new CountOptions(true, false, null, 10, 30, false, null);
            uint totalWordCount = 500;
            List<WordCountInfo> filteredCounts = new List<WordCountInfo>();
            filteredCounts.Add(new WordCountInfo("x", null, 100, 20F, 0F));
            filteredCounts.Add(new WordCountInfo("sb", null, 100, 20F, 0F));
            filteredCounts.Add(new WordCountInfo("sa", null, 100, 20F, 0F));
            filteredCounts.Add(new WordCountInfo("z", null, 100, 20F, 0F));
            filteredCounts.Add(new WordCountInfo("a", null, 100, 20F, 0F));
            List<WordCountInfo> finalCounts = new List<WordCountInfo>();
            target.Threshold(countOpt, totalWordCount, ref filteredCounts, ref finalCounts);

            // 5-way tie, so all words will be taken
            Assert.IsTrue(finalCounts.Count == 5);
        }

        /// <summary>
        ///A test for Threshold
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void ThresholdTest_TopN()
        {
            CountFilter_Accessor target = new CountFilter_Accessor();
            CountOptions countOpt = new CountOptions(true, false, null, 3, 100, false, null);
            uint totalWordCount = 500;
            List<WordCountInfo> filteredCounts = new List<WordCountInfo>();
            filteredCounts.Add(new WordCountInfo("x", null, 200, 40F, 0F));
            filteredCounts.Add(new WordCountInfo("sb", null, 100, 20F, 0F));
            filteredCounts.Add(new WordCountInfo("sa", null, 100, 20F, 0F));
            filteredCounts.Add(new WordCountInfo("z", null, 50, 10F, 0F));
            filteredCounts.Add(new WordCountInfo("a", null, 50, 10F, 0F));            
            List<WordCountInfo> finalCounts = new List<WordCountInfo>();
            target.Threshold(countOpt, totalWordCount, ref filteredCounts, ref finalCounts);
            
            Assert.IsTrue(finalCounts.Count == 3);
        }

        /// <summary>
        ///A test for Threshold
        ///</summary>
        [TestMethod()]
        [DeploymentItem("Reckoning.exe")]
        public void ThresholdTest_TopNTie()
        {
            CountFilter_Accessor target = new CountFilter_Accessor();
            CountOptions countOpt = new CountOptions(true, false, null, 4, 100, false, null);
            uint totalWordCount = 500;
            List<WordCountInfo> filteredCounts = new List<WordCountInfo>();
            filteredCounts.Add(new WordCountInfo("x", null, 100, 20F, 0F));
            filteredCounts.Add(new WordCountInfo("sb", null, 100, 20F, 0F));
            filteredCounts.Add(new WordCountInfo("sa", null, 100, 20F, 0F));
            filteredCounts.Add(new WordCountInfo("z", null, 100, 20F, 0F));
            filteredCounts.Add(new WordCountInfo("a", null, 100, 20F, 0F));
            List<WordCountInfo> finalCounts = new List<WordCountInfo>();
            target.Threshold(countOpt, totalWordCount, ref filteredCounts, ref finalCounts);

            // 5-way tie, so all words will be taken
            Assert.IsTrue(finalCounts.Count == 5);
        }

        /// <summary>
        ///A test for Run
        ///</summary>
        [TestMethod()]
        public void RunTest()
        {
            CountFilter target = new CountFilter();
            HashSet<StopWordInfo> sw = new HashSet<StopWordInfo>();
            sw.Add(new StopWordInfo("the"));
            CountOptions countOpt = new CountOptions(true, true, sw, 4, 100, true, "reference_data.xml");
            Dictionary<string, uint> rawCounts = new Dictionary<string, uint>();
            rawCounts.Add("go", 1);
            rawCounts.Add("going", 3);
            rawCounts.Add("cat", 2);
            rawCounts.Add("the", 5);
            rawCounts.Add("easter", 5);
            uint totalWordCount = 20;

            List<WordCountInfo> finalCounts;
            bool referenceDataOK ;             
            target.Run(countOpt, rawCounts, totalWordCount, out finalCounts, out referenceDataOK);

            bool correct = (finalCounts.Count == 3 && referenceDataOK);
            Assert.IsTrue(correct);
        }

        /// <summary>
        ///A test for Run
        ///</summary>
        [TestMethod()]
        public void RunTest_NoStem()
        {
            CountFilter target = new CountFilter();
            HashSet<StopWordInfo> sw = new HashSet<StopWordInfo>();
            sw.Add(new StopWordInfo("the"));
            CountOptions countOpt = new CountOptions(false, true, sw, 4, 100, true, "reference_data.xml");
            Dictionary<string, uint> rawCounts = new Dictionary<string, uint>();
            rawCounts.Add("go", 1);
            rawCounts.Add("going", 3);
            rawCounts.Add("cat", 2);
            rawCounts.Add("the", 5);
            rawCounts.Add("easter", 5);
            uint totalWordCount = 20;

            List<WordCountInfo> finalCounts;
            bool referenceDataOK;
            target.Run(countOpt, rawCounts, totalWordCount, out finalCounts, out referenceDataOK);

            bool correct = (finalCounts.Count == 4 && referenceDataOK);
            Assert.IsTrue(correct);
        }

        /// <summary>
        ///A test for Run
        ///</summary>
        [TestMethod()]
        public void RunTest_NoStopWords()
        {
            CountFilter target = new CountFilter();
            HashSet<StopWordInfo> sw = new HashSet<StopWordInfo>();
            sw.Add(new StopWordInfo("the"));
            CountOptions countOpt = new CountOptions(true, false, sw, 4, 100, true, "reference_data.xml");
            Dictionary<string, uint> rawCounts = new Dictionary<string, uint>();
            rawCounts.Add("go", 1);
            rawCounts.Add("going", 3);
            rawCounts.Add("cat", 2);
            rawCounts.Add("the", 5);
            rawCounts.Add("easter", 5);
            uint totalWordCount = 20;

            List<WordCountInfo> finalCounts;
            bool referenceDataOK;
            target.Run(countOpt, rawCounts, totalWordCount, out finalCounts, out referenceDataOK);

            bool correct = (finalCounts.Count == 4 && referenceDataOK);
            Assert.IsTrue(correct);
        }

        /// <summary>
        ///A test for Run
        ///</summary>
        [TestMethod()]
        public void RunTest_NoStemmingNoStopWords()
        {
            CountFilter target = new CountFilter();
            HashSet<StopWordInfo> sw = new HashSet<StopWordInfo>();
            sw.Add(new StopWordInfo("the"));
            CountOptions countOpt = new CountOptions(false, false, sw, 4, 100, true, "reference_data.xml");
            Dictionary<string, uint> rawCounts = new Dictionary<string, uint>();
            rawCounts.Add("go", 1);
            rawCounts.Add("going", 3);
            rawCounts.Add("cat", 2);
            rawCounts.Add("the", 5);
            rawCounts.Add("easter", 5);
            uint totalWordCount = 20;

            List<WordCountInfo> finalCounts;
            bool referenceDataOK;
            target.Run(countOpt, rawCounts, totalWordCount, out finalCounts, out referenceDataOK);

            bool correct = (finalCounts.Count == 4 && referenceDataOK);
            Assert.IsTrue(correct);
        }

        /// <summary>
        ///A test for Run
        ///</summary>
        [TestMethod()]
        public void RunTest_NoReference()
        {
            CountFilter target = new CountFilter();
            HashSet<StopWordInfo> sw = new HashSet<StopWordInfo>();
            sw.Add(new StopWordInfo("the"));
            CountOptions countOpt = new CountOptions(true, true, sw, 4, 100, false, "reference_data.xml");
            Dictionary<string, uint> rawCounts = new Dictionary<string, uint>();
            rawCounts.Add("go", 1);
            rawCounts.Add("going", 3);
            rawCounts.Add("cat", 2);
            rawCounts.Add("the", 5);
            rawCounts.Add("easter", 5);
            uint totalWordCount = 20;

            List<WordCountInfo> finalCounts;
            bool referenceDataOK;
            target.Run(countOpt, rawCounts, totalWordCount, out finalCounts, out referenceDataOK);

            bool correct = (finalCounts.Count == 3 && !referenceDataOK);
            Assert.IsTrue(correct);
        }

        /// <summary>
        ///A test for Run
        ///</summary>
        [TestMethod()]
        public void RunTest_BadReference()
        {
            CountFilter target = new CountFilter();
            HashSet<StopWordInfo> sw = new HashSet<StopWordInfo>();
            sw.Add(new StopWordInfo("the"));
            CountOptions countOpt = new CountOptions(true, true, sw, 4, 100, true, null);
            Dictionary<string, uint> rawCounts = new Dictionary<string, uint>();
            rawCounts.Add("go", 1);
            rawCounts.Add("going", 3);
            rawCounts.Add("cat", 2);
            rawCounts.Add("the", 5);
            rawCounts.Add("easter", 5);
            uint totalWordCount = 20;

            List<WordCountInfo> finalCounts;
            bool referenceDataOK;
            target.Run(countOpt, rawCounts, totalWordCount, out finalCounts, out referenceDataOK);

            bool correct = (finalCounts.Count == 3 && !referenceDataOK);
            Assert.IsTrue(correct);
        }
    }
}
